
#include <string.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>

#include "atom.h"
#include "drv_usart.h"

static void usart_buffered_send(SioBase* sio)
{
    Stm32l0Usart *usart = (Stm32l0Usart*)sio;

    usart_enable_tx_interrupt(usart->Protected.owner);
}


static void usart_blocking_send(SioBase* sio, const char *buffer, uint32_t size)
{
    Stm32l0Usart *usart = (Stm32l0Usart*)sio;

    for(int i=0; i < size; i++){
        usart_send_blocking(usart->Protected.owner, buffer[i]);
    }
}

static int usart_ioctl(SioBase*sio, int function, void* arg)
{
    return NG;
}

static int get_stop_bit(enSioStopBit stopBit)
{
    if(stopBit == ssb2Bit){
        return USART_STOPBITS_2;
    }else{
        return USART_STOPBITS_1;
    }
}

static int get_parity(enSioParity parity)
{
    int ret = USART_PARITY_NONE;
    switch(parity){
        case spNone:
        ret = USART_PARITY_NONE;
        break;
        case spOdd:
        ret = USART_PARITY_ODD;
        break;
        case spEven:
        ret = USART_PARITY_EVEN;
        break;
        default:
        break;
    }

    return (ret);
}

typedef struct {
    uint32_t owner;
    Stm32l0Usart *usart;
}Stm32UsartHandler;

static Stm32UsartHandler _usart_handler[(int)USART_MAX] = {
#ifdef BSP_USE_USART1    
    {USART1, NULL},
#endif
#ifdef BSP_USE_USART2    
    {USART2, NULL},
#endif
#ifdef BSP_USE_USART3        
    {USART3, NULL},
#endif
};

void usart_handler(Stm32l0Usart *sio)
{
    if((USART_ISR(sio->Protected.owner) & USART_ISR_RXNE) == USART_ISR_RXNE){
        uint8_t c = usart_recv(sio->Protected.owner);
        ringPut(&sio->Protected.ops.rxRing, (char*)&c, 1);
    }


    if((USART_ISR(sio->Protected.owner) & USART_ISR_TXE) == USART_ISR_TXE){
        int count = 0;
        char c;

        count = ringGet(&sio->Protected.ops.txRing, &c, 1);

        if( count > 0){
            usart_send(sio->Protected.owner, c);
        }else{
            usart_disable_tx_interrupt(sio->Protected.owner);
        }
    }
}

#ifdef BSP_USE_USART2

void usart2_handler(void)
{
    atomIntEnter();

    usart_handler(_usart_handler[USART2_INDEX].usart);

    atomIntExit(FALSE);
}

#pragma weak usart2_isr = usart2_handler

#endif

void Stm32UsartCreate(Stm32l0Usart* sio, const char*name, Stm32UsartConfig *config, uint32_t rxSize, uint32_t txSize) 
{
    _usart_handler[config->index].usart = sio;

    sio->Protected.owner = _usart_handler[config->index].owner;

    sio->Protected.ops.Ioctl = usart_ioctl;
    sio->Protected.ops.BufferedSend = usart_buffered_send;
    sio->Protected.ops.BlockingSend = usart_blocking_send;

    SioCreate(&sio->super, name, &config->param, &sio->Protected.ops, config->rxBuf, rxSize, config->txBuf, txSize);

    sio->Protected.config = config;

    //TODO：pin port
    rcc_peripheral_enable_clock(&RCC_IOPENR, RCC_IOPENR_IOPAEN); 
    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USART2EN);
    rcc_periph_clock_enable(RCC_USART2);

    usart_disable(sio->Protected.owner);
    gpio_mode_setup(GPIOA, GPIO_MODE_AF , GPIO_PUPD_NONE, GPIO2 | GPIO15);
    gpio_set_af(GPIOA, GPIO_AF4, GPIO2 | GPIO15);

    usart_set_baudrate(sio->Protected.owner, config->param.baud);
    usart_set_databits(sio->Protected.owner, config->param.dataBits);
    usart_set_parity(sio->Protected.owner, get_parity(config->param.parity));
    usart_set_stopbits(sio->Protected.owner, get_stop_bit(config->param.stopBit));
    usart_set_mode(sio->Protected.owner, USART_MODE_TX_RX);
    usart_set_flow_control(sio->Protected.owner, USART_FLOWCONTROL_NONE);

    usart_enable_rx_interrupt(sio->Protected.owner);
    usart_enable(sio->Protected.owner);
}
